//go:build js

package time

import (
	"runtime"

	"github.com/gopherjs/gopherjs/js"
)

// Make sure time.Unix func and time.Time struct it returns are always included with this package (despite DCE),
// because they're needed for internalization/externalization of time.Time/Date. See issue https://github.com/gopherjs/gopherjs/issues/279.
func init() {
	// avoid dead code elimination
	var _ Time = Unix(0, 0)
}

type runtimeTimer struct {
	i       int32
	when    int64
	period  int64
	f       func(any, uintptr)
	arg     any
	seq     uintptr
	timeout *js.Object
	active  bool
}

func now() (sec int64, nsec int32, mono int64) {
	n := runtimeNano()
	return n / int64(Second), int32(n % int64(Second)), n
}

func Sleep(d Duration) {
	c := make(chan struct{})
	js.Global.Call("$setTimeout", js.InternalObject(func() { close(c) }), int(d/Millisecond))
	<-c
}

func startTimer(t *runtimeTimer) {
	t.active = true
	diff := (t.when - runtimeNano()) / int64(Millisecond)
	if diff > 1<<31-1 { // math.MaxInt32
		return
	}
	if diff < 0 {
		diff = 0
	}
	t.timeout = js.Global.Call("$setTimeout", js.InternalObject(func() {
		t.active = false
		if t.period != 0 {
			t.when += t.period
			startTimer(t)
		}
		go t.f(t.arg, 0)
	}), diff+1)
}

func stopTimer(t *runtimeTimer) bool {
	js.Global.Call("clearTimeout", t.timeout)
	wasActive := t.active
	t.active = false
	return wasActive
}

func modTimer(t *runtimeTimer, when, period int64, f func(any, uintptr), arg any, seq uintptr) {
	stopTimer(t)
	t.when = when
	t.period = period
	t.f = f
	t.arg = arg
	t.seq = seq
	startTimer(t)
}

func resetTimer(t *runtimeTimer, when int64) bool {
	wasActive := t.active
	modTimer(t, when, t.period, t.f, t.arg, t.seq)
	return wasActive
}

func forceZipFileForTesting(zipOnly bool) {
}

var zoneSources = []string{
	runtime.GOROOT() + "/lib/time/zoneinfo.zip",
}

// indexByte is copied from strings package to avoid importing it (since the real time package doesn't).
func indexByte(s string, c byte) int {
	return js.InternalObject(s).Call("indexOf", js.Global.Get("String").Call("fromCharCode", c)).Int()
}
